package scalab.core.dependencies

import scala.collection.mutable.HashMap

//make new class for interactions extending map...
//change name so that it is oriented?
private[core] final class FilesInterDependencies extends HashMap[Dependency, InterDependency]{

	def require(target: Dependency, claimees: Iterable[Dependency]): FilesInterDependencies = {
		val rel = getInterDependency(target, false)
		var rels: List[InterDependency] = Nil
		++= (claimees map {c => 
			rels = getInterDependency(c, false) :: rels
			(c, rels.head)
		})
		
		update(target, rel += rels)
		/*Reporter.warning("rel: " + rel)
		Reporter.warning("rels: " + rels)*/
		this
	}

	def related(claimees: Iterable[Dependency]): FilesInterDependencies = {
		if(!claimees.isEmpty){
			var lst: List[Dependency] = claimees.toList
			var head: List[Dependency] = Nil
			var tail: List[Dependency] = lst.tail
			lst foreach {c => 
				require(c, tail)
				head = c :: head
				tail = tail.tail
			}
		}
		this
	}

	/**
	*	Returns the relation corresponding to the specified resource. If the 
	*	relations does not exist, it is instantiated and inserted in the map.
	*/
	def getInterDependency(dep: Dependency): InterDependency = getInterDependency(dep, true)

	/**
	* Returns the relation corresponding to the specified resource. If the 
	*	relations does not exist, it is instantiated. In this case, it is 
	*	also inserted in the map if the <code>insert</code> parameter is set to true. 
	*	This is more efficient to set <code>insert</code> to false in the case 
	*	we know that we will update the map later but before querying the map again.
	*/
	def getInterDependency(dep: Dependency, insert: Boolean): InterDependency = get(dep) match{
		case None => 
			val rel = new InterDependency(dep)
			if(insert)
				update(dep, rel)
			rel
		case Some(r) => r
	}

	def getAll(deps: Iterable[Dependency]): List[InterDependency] = {
		//todo: sort deps and keySet and walk in-order for better performances
		var res: List[InterDependency] = Nil
		elements foreach {e =>
			if(deps exists {d => d == e._1})
				res = e._2 :: res
		}
		res
	}

	def getAllOptions(deps: List[Dependency]): List[Option[InterDependency]] = 
		deps map {d => get(d)}
}

//change to a directed name? (Connection)


@serializable
final class InterDependency(var dependency: Dependency){

	var children: List[InterDependency] = Nil

	def childrenDependencies: List[Dependency] =
		children map {c => c.dependency}

	def allChildrenDependencies: List[Dependency] = 
		if(children.isEmpty)Nil
		else children flatMap {c => c.dependency :: c.allChildrenDependencies}

	/*def propagate(visited: List[Relation]): List[Relation] = {
		val fresh = children diff visited //diff is deprecated: use -- instead when available...
		val newVisited = visited ::: fresh
		fresh flatMap {f => f.propagate(newVisited)}
	}*/

	/**
	*	Adds a list of relations to <code>this</code> relation. In order 
	*	to optimize further computations, duplicates are removed.
	*	@returns <code>this</code> altered <code>Relation</code>
	*/
	def +=(rels: List[InterDependency]): InterDependency = {
		children = children ::: rels//(children diff rels) //use -- when available (diff deprecated)
		this
	}

	/**
	* Indicates whether <code>that</code> is to be considered equal with 
	*	<code>this Relation</code>. This is true iff <code>that</code> is 
	*	also a <code>Relation</code> and it points to the same canonical 
	*	file than <code>this</code>.
	*	@see Resource#equals(Any)
	*/
	override def equals(that: Any): Boolean = 
		//for performances, we call equals (in opposition to ==) 
		//since neither that nor this can be null!
		that.isInstanceOf[InterDependency] && that.asInstanceOf[InterDependency].dependency.equals(dependency)

	override def toString: String = dependency.canonicalPath + " >> (" + children.mkString("",", ","") + ")"

	def require(d: Dependency): Boolean = {
		(d == dependency) || (children exists {c => c require d})
	}

	def requireAny(deps: Iterable[Dependency]): Boolean = {
		(deps exists {d => d == dependency}) || (children exists {c => c requireAny deps})
	}
}
